﻿Imports System.Drawing

Public Class ControlContainer
  Private _dpiFactor As Single = 0.0F

  Private _config As New Configuration
  Private _currentSurface As Integer = 0

  Private _floatingMessageIcons As List(Of Bitmap) = Nothing
  Private _currentFloatingMessageIconIndex As Integer = -1
  Private _floatingMessage As String = ""
  Private _lastEnabled As Boolean = False
  Private _lastVisible As Boolean = False
  Private _isFloatingMessageVisible As Boolean = False

  Private _brBg As New SolidBrush(Me.BackColor)
  Private _brFg As New SolidBrush(Me.ForeColor)

  Public Event ButtonDown(ByVal func As Integer, ByVal param As Integer)
  Public Event ButtonUp(ByVal func As Integer, ByVal param As Integer)
  Public Event ButtonDrag(ByVal func As Integer, ByVal param As Integer)
  Public Event RefreshPlayStates()
  Public Event DelayedHideFinished()


  Public Overrides Property BackColor() As System.Drawing.Color
    Get
      Return MyBase.BackColor
    End Get
    Set(ByVal value As System.Drawing.Color)
      MyBase.BackColor = value
      Me._brBg = New SolidBrush(value)
    End Set
  End Property

  Public Overrides Property ForeColor() As System.Drawing.Color
    Get
      Return MyBase.ForeColor
    End Get
    Set(ByVal value As System.Drawing.Color)
      MyBase.ForeColor = value
      Me._brFg = New SolidBrush(value)
    End Set
  End Property


  Public Sub New()
    InitializeComponent()
    Me._dpiFactor = Me.AutoScaleDimensions.Height / 192.0F
    Me._config.ActualScaleFactor = Me._dpiFactor
    Me.LoadControlsFromINI()
  End Sub

  Public Sub LoadControlsFromINI()
    Try
      Me._config.LoadControlsFromINI()
    Catch ex As Exception
      Windows.Forms.MessageBox.Show(Language.GetLanguageString("ControlSurfaceError") & " " & ex.Message)
      ErrorLog.WriteToErrorLog("ControlContainer - Configuration - LoadControlsFromINI :: " & ex.ToString)
    End Try
  End Sub


  Public ReadOnly Property ActualScaleFactor()
    Get
      Return Me._dpiFactor
    End Get
  End Property

  Public Property FloatingMessageIcons() As List(Of Bitmap)
    Get
      Return Me._floatingMessageIcons
    End Get
    Set(ByVal value As List(Of Bitmap))
      Me._floatingMessageIcons = value
    End Set
  End Property

  Public Sub ShowFloatingMessage(ByVal index As Integer, ByVal msg As String)
    Me.TimerFloatingMessageHideAfter.Enabled = False

    Me._currentFloatingMessageIconIndex = index
    Me._floatingMessage = msg

    Me._lastEnabled = Me.Enabled
    Me._lastVisible = Me.Visible

    Me._isFloatingMessageVisible = True

    Me.InvalidateSmart()

    Me.Enabled = True
    Me.Visible = True

    Me.BringToFront()
  End Sub

  Public Sub HideFloatingMessage(Optional ByVal afterms As Integer = 0, Optional ByVal forceVisible As Boolean = False)
    If forceVisible Then
      Me._lastVisible = True
      Me._lastEnabled = True
    End If

    If afterms <= 0 Then
      Me.DoHideFloatingMessage()
    Else
      Me.TimerFloatingMessageHideAfter.Enabled = False
      Me.TimerFloatingMessageHideAfter.Interval = afterms
      Me.TimerFloatingMessageHideAfter.Enabled = True
    End If
  End Sub

  Private Sub DoHideFloatingMessage()
    Me._currentFloatingMessageIconIndex = -1

    Me._isFloatingMessageVisible = False

    Me.InvalidateSmart()

    Me.Enabled = Me._lastEnabled
    Me.Visible = Me._lastVisible
  End Sub





  Public ReadOnly Property Surfaces() As List(Of ControlSurface)
    Get
      Return Me._config.Surfaces
    End Get
  End Property

  Public Property CurrentSurface() As Integer
    Get
      Return Me._currentSurface
    End Get
    Set(ByVal value As Integer)
      Me._currentSurface = value
      Me.ClearButtonStates()
      RaiseEvent RefreshPlayStates()
      Me.InvalidateSmart()
    End Set
  End Property






  Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
    Static Dim bufWidth As Integer = 0
    Static Dim bufHeight As Integer = 0
    Static Dim buffer As Bitmap = Nothing
    Static Dim strFmt As New StringFormat()
    Static Dim fmFont As New Drawing.Font("Tahoma", 12, Drawing.FontStyle.Bold)

    If buffer Is Nothing OrElse Me.Width <> bufWidth OrElse Me.Height <> bufHeight Then
      bufWidth = Me.Width
      bufHeight = Me.Height

      If buffer IsNot Nothing Then
        buffer.Dispose()
      End If

      buffer = New Bitmap(bufWidth, bufHeight)

      strFmt.Alignment = StringAlignment.Center
    End If

    Dim g As Graphics = Graphics.FromImage(buffer)

    g.FillRectangle(Me._brBg, 0, 0, bufWidth, bufHeight)

    If Me._isFloatingMessageVisible Then
      If Me._currentFloatingMessageIconIndex >= 0 AndAlso Me._currentFloatingMessageIconIndex < Me._floatingMessageIcons.Count Then
        Dim textHeight As Integer = g.MeasureString(Me._floatingMessage, fmFont).Height
        Dim imgWidth As Integer = Me._floatingMessageIcons(Me._currentFloatingMessageIconIndex).Width * Me._dpiFactor
        Dim imgHeight As Integer = Me._floatingMessageIcons(Me._currentFloatingMessageIconIndex).Height * Me._dpiFactor
        Dim totalHeight = textHeight + imgHeight
        Dim spacing As Integer = Me.Height - totalHeight

        If totalHeight < Me.Height Then
          spacing = spacing >> 1
        End If

        Dim iconRectDest As New Rectangle((Me.Width - imgWidth) >> 1, spacing, imgWidth, imgHeight)
        Dim iconRectSrc As New Rectangle(0, 0, Me._floatingMessageIcons(Me._currentFloatingMessageIconIndex).Width, Me._floatingMessageIcons(Me._currentFloatingMessageIconIndex).Height)

        g.DrawImage(Me._floatingMessageIcons(Me._currentFloatingMessageIconIndex), iconRectDest, iconRectSrc, GraphicsUnit.Pixel)
        g.DrawString(Me._floatingMessage, fmFont, Me._brFg, bufWidth >> 1, iconRectDest.Y + iconRectDest.Height, strFmt)
      End If
    Else
      'g.DrawString(Me._currentSurface, fmFont, brFg, 10, 10)
      If Me._currentSurface >= 0 AndAlso Me._currentSurface < Me.Surfaces.Count Then
        Me.Surfaces(Me._currentSurface).DrawSurface(g, New Rectangle(0, 0, Me.Width, Me.Height), Me._dpiFactor)
      End If
    End If

    g.Dispose()
    e.Graphics.DrawImage(buffer, 0, 0)
  End Sub

  Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
    ' Do nothing
  End Sub



  Public Sub ClearButtonStates()
    For Each sc As ControlSurface In Me._config.Surfaces
      For Each s As ControlScene In sc.Scenes
        For Each st As ControlRow In s.Rows
          For Each b As ControlButton In st.Buttons
            b.ButtonClear()
          Next
        Next
      Next
    Next
  End Sub

  Public Sub InvalidateSmart()
    Me.TimerInvalidate.Enabled = True
  End Sub

  Private Sub TimerInvalidate_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerInvalidate.Tick
    Me.TimerInvalidate.Enabled = False
    Me.Invalidate()
  End Sub

  Private Sub TimerFloatingMessageHideAfter_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TimerFloatingMessageHideAfter.Tick
    Me.TimerFloatingMessageHideAfter.Enabled = False
    Me.DoHideFloatingMessage()
    RaiseEvent DelayedHideFinished()
  End Sub

  Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
    If Not Me._isFloatingMessageVisible Then
      If Me._currentSurface >= 0 AndAlso Me._currentSurface < Me._config.Surfaces.Count Then
        With Me._config.Surfaces(Me._currentSurface).CurrentScene
          For Each st As ControlRow In .Rows
            For Each b As ControlButton In st.Buttons
              If b.IsActive AndAlso b.HitRectangle.Contains(e.X, e.Y) Then
                b.ButtonDown(e.X)
                RaiseEvent ButtonDown(b.FunctionIndex, b.FunctionParameter)
              End If
            Next
          Next
        End With

        Me.InvalidateSmart()
      End If
    End If

    MyBase.OnMouseDown(e)
  End Sub

  Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
    Dim doInvalidate As Boolean = False

    If Not Me._isFloatingMessageVisible Then
      If Me._currentSurface >= 0 AndAlso Me._currentSurface < Me._config.Surfaces.Count Then
        With Me._config.Surfaces(Me._currentSurface).CurrentScene
          For Each st As ControlRow In .Rows
            For Each b As ControlButton In st.Buttons
              If b.Type = ControlButton.ButtonType.Slider AndAlso b.IsDown AndAlso b.IsActive Then
                b.ButtonDrag(e.X)
                RaiseEvent ButtonDrag(b.FunctionIndex, b.FunctionParameter)
                doInvalidate = True
              End If
            Next
          Next
        End With
      End If
    End If

    If doInvalidate Then
      Me.InvalidateSmart()
    End If

    MyBase.OnMouseMove(e)
  End Sub

  Protected Overrides Sub OnMouseUp(ByVal e As System.Windows.Forms.MouseEventArgs)
    If Not Me._isFloatingMessageVisible Then
      If Me._currentSurface >= 0 AndAlso Me._currentSurface < Me._config.Surfaces.Count Then
        With Me._config.Surfaces(Me._currentSurface).CurrentScene
          For Each st As ControlRow In .Rows
            For Each b As ControlButton In st.Buttons
              If b.IsDown AndAlso b.IsActive AndAlso (b.Type = ControlButton.ButtonType.Slider OrElse b.HitRectangle.Contains(e.X, e.Y)) Then
                b.ButtonUp(e.X)
                RaiseEvent ButtonUp(b.FunctionIndex, b.FunctionParameter)
              End If
            Next
          Next
        End With
      End If
    Else
      Me.TimerFloatingMessageHideAfter.Enabled = False
      Me.DoHideFloatingMessage()
      RaiseEvent DelayedHideFinished()
    End If

    Me.ClearButtonStates()
    Me.InvalidateSmart()

    MyBase.OnMouseUp(e)
  End Sub

  Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
    Me.Invalidate() ' Can't do a "smart" invalidate since all timers get disabled when the control does
    MyBase.OnResize(e)
  End Sub

End Class

